using System.Collections;
using GHIElectronics.NETMF.Glide;
using GHIElectronics.NETMF.Glide.UI;
using Melody_Glider.MelodyContent;
using Microsoft.SPOT.Presentation.Media;
using Colors = GHIElectronics.NETMF.Glide.Colors;

namespace Melody_Glider.GUIContent
{
    internal class NoteInputWindow: WindowFrame //todo: somebody told me to turn note adding quicker
    {                                           //also I have to try do further improvements and cleanups
        private readonly GUI _gui;
        private readonly SystemState _conditions;
        private Note _tempNote;
        private bool _isNote;
        private bool _sharp;
        private bool _flat;
        private bool _staccato;
        private bool _dotted;
        private bool _ligature;
        private bool _flatDisabled;
        private bool _sharpDisabled;
        private bool _ligatureDisabled;
        private bool _dottedDisabled;
        private bool _pitchEnabled;
        private string _selectedImage;
        private string _selectedPitch;
        private string _selectedNoteDuration;
        private static readonly string[] NoteSymbols = new[] { "C", "D", "E", "F", "G", "A", "B" };

        private readonly string[] _noteNames = new[]
                                               {
                                                   "fullNote", "halfNote", "quarterNote", "eighthNote", "sixteenthNote",
                                                   "fullRest", "halfRest", "quarterRest", "eighthRest", "sixteenthRest",
                                               };

        private readonly Hashtable _imageResources = new Hashtable //todo: think about hashtables
        {
            {"fullNote", Resources.BitmapResources.fullNote},
            {"fullNote_1", Resources.BitmapResources.fullNote_1},
            {"halfNote", Resources.BitmapResources.halfNote},
            {"halfNote_1", Resources.BitmapResources.halfNote_1},
            {"quarterNote", Resources.BitmapResources.quarterNote},
            {"quarterNote_1", Resources.BitmapResources.quarterNote_1},
            {"eighthNote", Resources.BitmapResources.eighthNote},
            {"eighthNote_1", Resources.BitmapResources.eighthNote_1},
            {"sixteenthNote", Resources.BitmapResources.sixteenthNote},
            {"sixteenthNote_1", Resources.BitmapResources.sixteenthNote_1},
            {"fullRest", Resources.BitmapResources.fullRest},
            {"fullRest_1", Resources.BitmapResources.fullRest_1},
            {"halfRest", Resources.BitmapResources.halfRest},
            {"halfRest_1", Resources.BitmapResources.halfRest_1},
            {"quarterRest", Resources.BitmapResources.quarterRest},
            {"quarterRest_1", Resources.BitmapResources.quarterRest_1},
            {"eighthRest", Resources.BitmapResources.eighthRest},
            {"eighthRest_1", Resources.BitmapResources.eighthRest_1},
            {"sixteenthRest", Resources.BitmapResources.sixteenthRest},
            {"sixteenthRest_1", Resources.BitmapResources.sixteenthRest_1},
            {"sharp", Resources.BitmapResources.sharp},
            {"sharp_1", Resources.BitmapResources.sharp_1},
            {"flat", Resources.BitmapResources.flat},
            {"flat_1", Resources.BitmapResources.flat_1},
            {"dotted", Resources.BitmapResources.dotted},
            {"dotted_1", Resources.BitmapResources.dotted_1},
            {"staccato", Resources.BitmapResources.staccato},
            {"staccato_1", Resources.BitmapResources.staccato_1},
            {"ligature", Resources.BitmapResources.ligature},
            {"ligature_1", Resources.BitmapResources.ligature_1}
        };
        
        private readonly Hashtable _pitches = new Hashtable
                                              {
                                                  {Pitch.C, 7},
                                                  {Pitch.Cs, 7},
                                                  {Pitch.D, 8},
                                                  {Pitch.Eb, 9},
                                                  {Pitch.E, 9},
                                                  {Pitch.F, 10},
                                                  {Pitch.Fs, 10},
                                                  {Pitch.G, 11},
                                                  {Pitch.Gs, 11},
                                                  {Pitch.A, 12},
                                                  {Pitch.Bb, 13},
                                                  {Pitch.B, 13}
                                              };
        
        public NoteInputWindow(GUI gui, SystemState state)
        {
            _gui = gui;
            _conditions = state;
        }

        protected override void SophisticatedInit()
        {
            _selectedImage = "fullNote";
            _selectedNoteDuration = "full";
            _selectedPitch = "Note7";
            _isNote = true;
            _pitchEnabled = true;
            //redundant, bool initial value is false
            /*_sharpDisabled = false;
            _flatDisabled = false;
            _dottedDisabled = false;
            _ligatureDisabled = false;
            _sharp = false;
            _flat = false;
            _staccato = false;
            _dotted = false;
            _ligature = false;*/

            DrawPitchField();
        }

        private void DrawPitchField()
        {
            var drawer = GetCanvas();
            ThisWindow.AddChild(drawer);

            drawer.DrawRectangle(Colors.Black, 1, 40, 90, 241, 89, 0, 0, Colors.White, 40, 90, Colors.White, 241, 89, 224);

            for (var i = 0; i < 10; i++)
            {
                if (i >= 1 && i <= 5)
                    drawer.DrawLine(Colors.Black, 1, 41, 90 + 8 * (i + 1), 279, 90 + 8 * (i + 1));
                else
                    drawer.DrawLine(Colors.LightGray, 1, 41, 90 + 8 * (i + 1), 279, 90 + 8 * (i + 1));
            }

            DrawPitches();
        }

        private Canvas GetCanvas()
        {
            return new Canvas { Parent = ThisWindow, X = 0, Y = 0, Width = 320, Height = 240, Name = "Staff" };
        }

        private void DrawPitches()
        {
            for (var i = 0; i < 21; i++)
            {
                var noteSymbol = new Image("Note" + i, 255, 24 * (i % 7) + 81, 171 - 4 * i, 28, 16);
                noteSymbol.Bitmap = Resources.GetBitmap(Resources.BitmapResources.note);
                
                var backColor = noteSymbol.Bitmap.GetPixel(1, 1);
                noteSymbol.Bitmap.MakeTransparent(backColor);
                noteSymbol.TapEvent += PitchTapEvent;

                ThisWindow.AddChild(noteSymbol);
            }
        }

        protected override void PrepareToMain()
        {
            if (_conditions.ReplaceMenu)
                LoadSelectedNoteData();

            Update();

            TogglePitch(_selectedPitch, true);
            ToggleImage(_selectedImage, true);
        }

        private void LoadSelectedNoteData()
        {
            var analyzedOne = _conditions.MelodyBuffer.GetNote(_conditions.SelectedNote);
            
            if (analyzedOne.IsLigature())
            {
                _ligature = true;
                ToggleImage("ligature", true);
            }
            if (analyzedOne.IsDotted())
            {
                _dotted = true;
                ToggleImage("dotted", true);
            }

            if (analyzedOne.IsRest())
            {
                _isNote = false;
                _selectedPitch = "Note7";
                _selectedImage = (string)Duration.Durations[analyzedOne.GetDuration()] + "Rest";
            }
            else
            {
                if (analyzedOne.IsFlat()) //this is here because rest cannot be flat nor sharp nor with staccato
                {
                    _flat = true;
                    ToggleImage("flat", true);
                }
                if (analyzedOne.IsSharp())
                {
                    _sharp = true;
                    ToggleImage("sharp", true);
                }
                if (analyzedOne.IsStaccato())
                {
                    _staccato = true;
                    ToggleImage("staccato", true);
                }

                _isNote = true;
                _selectedPitch = "Note" + ((int)_pitches[analyzedOne.GetPitch().Symbol] + 7 * analyzedOne.GetPitch().OctaveShift);
                _selectedImage = (string)Duration.Durations[analyzedOne.GetDuration()] + "Note";
            }

            _selectedNoteDuration = (string)Duration.Durations[analyzedOne.GetDuration()];
        }

        private void Update() //todo: make this look more clear 'cause it's awful
        {
            if (_isNote)
            {
                if (!_pitchEnabled)
                    EnablePitchSelection();

                if (!_dottedDisabled)
                    _gui.ToggleElement("dotted", ThisWindow, true);
                if (!_ligatureDisabled)
                _gui.ToggleElement("ligature", ThisWindow, true);

                if (!_dotted && !_ligature)
                    _gui.ToggleElement("staccato", ThisWindow, true);

                switch (int.Parse(_selectedPitch.Substring(4)) % 7)
                {
                    case 0:
                        {
                            _gui.ToggleElement("sharp", ThisWindow, true);
                            _sharpDisabled = false;
                            _gui.ToggleElement("flat", ThisWindow, false);
                            _flatDisabled = true;
                            if (_flat)
                            {
                                ToggleImage("flat", false);
                                _flat = false;
                            }
                            break;
                        }
                    case 1:
                        {
                            _gui.ToggleElement("sharp", ThisWindow, false);
                            _sharpDisabled = true;
                            if (_sharp)
                            {
                                ToggleImage("sharp", false);
                                _sharp = false;
                            }
                            _gui.ToggleElement("flat", ThisWindow, false);
                            _flatDisabled = true;
                            if (_flat)
                            {
                                ToggleImage("flat", false);
                                _flat = false;
                            }
                            break;
                        }
                    case 2:
                        {
                            _gui.ToggleElement("flat", ThisWindow, true);
                            _flatDisabled = false;
                            _gui.ToggleElement("sharp", ThisWindow, false);
                            _sharpDisabled = true;
                            if (_sharp)
                            {
                                ToggleImage("sharp", false);
                                _sharp = false;
                            }
                            break;
                        }
                    case 3:
                        {
                            _gui.ToggleElement("sharp", ThisWindow, true);
                            _sharpDisabled = false;
                            _gui.ToggleElement("flat", ThisWindow, false);
                            _flatDisabled = true;
                            if (_flat)
                            {
                                ToggleImage("flat", false);
                                _flat = false;
                            }
                            break;
                        }
                    case 4:
                        {
                            _gui.ToggleElement("sharp", ThisWindow, true);
                            _sharpDisabled = false;
                            _gui.ToggleElement("flat", ThisWindow, false);
                            _flatDisabled = true;
                            if (_flat)
                            {
                                ToggleImage("flat", false);
                                _flat = false;
                            }
                            break;
                        }
                    case 5:
                        {
                            _gui.ToggleElement("sharp", ThisWindow, false);
                            _sharpDisabled = true;
                            if (_sharp)
                            {
                                ToggleImage("sharp", false);
                                _sharp = false;
                            }
                            _gui.ToggleElement("flat", ThisWindow, false);
                            _flatDisabled = true;
                            if (_flat)
                            {
                                ToggleImage("flat", false);
                                _flat = false;
                            }
                            break;
                        }
                    case 6:
                        {
                            _gui.ToggleElement("flat", ThisWindow, true);
                            _flatDisabled = false;
                            _gui.ToggleElement("sharp", ThisWindow, false);
                            _sharpDisabled = true;
                            if (_sharp)
                            {
                                ToggleImage("sharp", false);
                                _sharp = false;
                            }
                            break;
                        }
                }
            }
            else
            {
                if (_pitchEnabled)
                    DisablePitchSelection();

                _gui.ToggleElement("dotted", ThisWindow, true);
                _gui.ToggleElement("ligature", ThisWindow, true);

                if (_staccato)
                {
                    ToggleImage("staccato", false);
                    _staccato = false;
                }
                _gui.ToggleElement("staccato", ThisWindow, false);
                
                if (_flat)
                {
                    ToggleImage("flat", false);
                    _flat = false;
                    _flatDisabled = true;
                }
                _gui.ToggleElement("flat", ThisWindow, false);

                if (_sharp)
                {
                    ToggleImage("sharp", false);
                    _sharp = false;
                    _sharpDisabled = true;
                }
                _gui.ToggleElement("sharp", ThisWindow, false);
            }
        }

        private void DisablePitchSelection()
        {
            for (var i = 0; i < 21; i++)
            {
                var noteSymbol = (Image)ThisWindow.GetChildByName("Note" + i);
                noteSymbol.Enabled = false;
                noteSymbol.Alpha = 64;
            }

            _pitchEnabled = false;

            if (Glide.MainWindow != ThisWindow) //to avoid too quick flush to the screen
                return;

            ThisWindow.Invalidate(); //todo: I suppose that I will dramatically reduce the number of usings of Invalidate() to make everything look faster
        }

        private void EnablePitchSelection()
        {
            for (var i = 0; i < 21; i++)
            {
                var noteSymbol = (Image)ThisWindow.GetChildByName("Note" + i);
                noteSymbol.Enabled = true;
                noteSymbol.Alpha = 255;
            }

            _pitchEnabled = true;

            if (Glide.MainWindow != ThisWindow) //to avoid too quick flush to the screen
                return;

            ThisWindow.Invalidate();
        }

        protected override void InitButtons() //got hashtable?
        {
            Color backColor;

            for (var i = 0; i < 10; i++)
            {
                var noteImg = (Image)ThisWindow.GetChildByName(_noteNames[i]);
                noteImg.Bitmap = Resources.GetBitmap((Resources.BitmapResources)_imageResources[_noteNames[i]]);
                backColor = noteImg.Bitmap.GetPixel(0, 0);
                noteImg.Bitmap.MakeTransparent(backColor);
                noteImg.TapEvent += NoteTapEvent;
            }

            var sharpImg = (Image)ThisWindow.GetChildByName("sharp");
            sharpImg.Bitmap = Resources.GetBitmap(Resources.BitmapResources.sharp);
            backColor = sharpImg.Bitmap.GetPixel(0, 0);
            sharpImg.Bitmap.MakeTransparent(backColor);
            sharpImg.TapEvent += SharpImgTapEvent;

            var flatImg = (Image)ThisWindow.GetChildByName("flat");
            flatImg.Bitmap = Resources.GetBitmap(Resources.BitmapResources.flat);
            backColor = flatImg.Bitmap.GetPixel(0, 0);
            flatImg.Bitmap.MakeTransparent(backColor);
            flatImg.TapEvent += FlatImgTapEvent;

            var dottedImg = (Image)ThisWindow.GetChildByName("dotted");
            dottedImg.Bitmap = Resources.GetBitmap(Resources.BitmapResources.dotted);
            backColor = dottedImg.Bitmap.GetPixel(0, 0);
            dottedImg.Bitmap.MakeTransparent(backColor);
            dottedImg.TapEvent += DottedImgTapEvent;

            var staccatoImg = (Image)ThisWindow.GetChildByName("staccato");
            staccatoImg.Bitmap = Resources.GetBitmap(Resources.BitmapResources.staccato);
            backColor = staccatoImg.Bitmap.GetPixel(0, 0);
            staccatoImg.Bitmap.MakeTransparent(backColor);
            staccatoImg.TapEvent += StaccatoImgTapEvent;

            var ligatureImg = (Image)ThisWindow.GetChildByName("ligature");
            ligatureImg.Bitmap = Resources.GetBitmap(Resources.BitmapResources.ligature);
            backColor = ligatureImg.Bitmap.GetPixel(0, 0);
            ligatureImg.Bitmap.MakeTransparent(backColor);
            ligatureImg.TapEvent += LigatureImgTapEvent;

            var okBtn = (Button)ThisWindow.GetChildByName("OKButton");
            okBtn.TapEvent += OkBtnTapEvent;

            var cancelBtn = (Button)ThisWindow.GetChildByName("CancelButton");
            cancelBtn.TapEvent += CancelBtnTapEvent;
        }

        private void NoteTapEvent(object sender)
        {
            var tappedImg = (Image)sender;

            _isNote = tappedImg.Name.Substring(tappedImg.Name.Length - 4) == "Note";

            if (_selectedNoteDuration == tappedImg.Name)
                return;

            ToggleImage(_selectedImage, false);

            _selectedImage = tappedImg.Name;
            _selectedNoteDuration = tappedImg.Name.Substring(0, tappedImg.Name.Length - 4);

            ToggleImage(_selectedImage, true);

            Update();
        }

        private void PitchTapEvent(object sender)
        {
            var tappedOne = (Image)sender;

            if (_selectedPitch == tappedOne.Name)
                return;

            TogglePitch(_selectedPitch, false);

            _selectedPitch = tappedOne.Name;

            TogglePitch(_selectedPitch, true);

            Update();
        }
        
        private void LigatureImgTapEvent(object sender) //todo: this and four above should be cleaned up
        {
            _ligature = !_ligature;
            if (_ligature)
            {
                if (_staccato)
                    ToggleImage("staccato", false);
                ToggleImage("ligature", true);
                if (_dotted || !_isNote)
                    return;
                _gui.ToggleElement("staccato", ThisWindow, false);
            }
            else
            {
                ToggleImage("ligature", false);
                if (_dotted || !_isNote)
                    return;
                _gui.ToggleElement("staccato", ThisWindow, true);
            }
        }

        private void StaccatoImgTapEvent(object sender)
        {
            _staccato = !_staccato;
            if (_staccato)
            {
                if (_ligature)
                    ToggleImage("ligature", false);
                _gui.ToggleElement("ligature", ThisWindow, false);
                if (_dotted)
                    ToggleImage("dotted", false);
                _gui.ToggleElement("dotted", ThisWindow, false);
                ToggleImage("staccato", true);
            }
            else
            {
                _gui.ToggleElement("ligature", ThisWindow, true);
                _gui.ToggleElement("dotted", ThisWindow, true);
                ToggleImage("staccato", false);
            }

            _dottedDisabled = true;
            _ligatureDisabled = true;
        }

        private void DottedImgTapEvent(object sender)
        {
            _dotted = !_dotted;
            if (_dotted)
            {
                if (_staccato)
                    ToggleImage("staccato", false);
                ToggleImage("dotted", true);
                if (_ligature || !_isNote)
                    return;
                _gui.ToggleElement("staccato", ThisWindow, false);
            }
            else
            {
                ToggleImage("dotted", false);
                if (_ligature || !_isNote)
                    return;
                _gui.ToggleElement("staccato", ThisWindow, true);
            }
        }

        private void FlatImgTapEvent(object sender)
        {
            _flat = !_flat;
            if (_flat)
            {
                _gui.ToggleElement("sharp", ThisWindow, false);
                ToggleImage("flat", true);
            }
            else
            {
                if (!_sharpDisabled)
                    _gui.ToggleElement("sharp", ThisWindow, true);
                ToggleImage("flat", false);
            }
        }

        private void SharpImgTapEvent(object sender)
        {
            _sharp = !_sharp;
            if (_sharp)
            {
                _gui.ToggleElement("flat", ThisWindow, false);
                ToggleImage("sharp", true);
            }
            else
            {
                if (!_flatDisabled)
                    _gui.ToggleElement("flat", ThisWindow, true);
                ToggleImage("sharp", false);
            }
        }

        private void CancelBtnTapEvent(object sender)
        {
            _gui.EditorWindow.SetToMain();
            Reset();
        }

        private void Reset()
        {
            ToggleImage(_selectedImage, false);

            _selectedImage = "fullNote";
            _selectedNoteDuration = "full";

            TogglePitch(_selectedPitch, false);

            _selectedPitch = "Note7";
            _isNote = true;

            if (_sharp)
            {
                ToggleImage("sharp", false); //todo: maybe invoke this with _sharp instead of false
                _sharp = false;
            }
            if (_flat)
            {
                ToggleImage("flat", false); //todo: etc
                _flat = false;
            }
            if (_staccato)
            {
                ToggleImage("staccato", false);
                _staccato = false;
            }
            if (_dotted)
            {
                ToggleImage("dotted", false);
                _dotted = false;
            }
            if (_ligature)
            {
                ToggleImage("ligature", false);
                _ligature = false;
            }
        }

        private void OkBtnTapEvent(object sender)
        {
            _tempNote = new Note(null, 0.0, _ligature, _dotted, _staccato);
            _tempNote.SetDuration((double)Duration.Durations[_selectedNoteDuration]);

            if (_isNote)
            {
                var newOctaveShift = 0;

                //this can be moved to something like SetNewOctaveShift(string pitchIdx)
                if (int.Parse(_selectedPitch.Substring(4)) < 7)
                    newOctaveShift = -1;
                if (int.Parse(_selectedPitch.Substring(4)) >= 7 && int.Parse(_selectedPitch.Substring(4)) < 14)
                    newOctaveShift = 0;
                if (int.Parse(_selectedPitch.Substring(4)) >= 14)
                    newOctaveShift = 1;

                var octaveModifier = "";
                if (_gui.NoteInputWindow._sharp)
                    octaveModifier = "#";
                if (_gui.NoteInputWindow._flat)
                    octaveModifier = "b";

                _tempNote.SetPitch(new Pitch((double)Pitch.Symbols[NoteSymbols[int.Parse(_selectedPitch.Substring(4))%7] + octaveModifier], newOctaveShift));
            }
            else
                _tempNote.SetPitch(new Pitch((double)Pitch.Symbols["R"], 0));

            if (_conditions.ReplaceMenu)
            {
                _conditions.MelodyBuffer.ReplaceNote(_tempNote, _conditions.SelectedNote);

                if (_conditions.SelectedNote - _gui.EditorWindow.DrawingStartIndex == _gui.EditorWindow.DisplayedNoteCounter -1 && _gui.EditorWindow.XPos + _gui.EditorWindow.NoteWidth(_tempNote) + EditorWindow.CursorWidth > EditorWindow.MelodyFieldBound)
                    _gui.EditorWindow.DrawingStartIndex++;
            }
            else
            {
                if (_gui.Cursor.IsAtStart() && _conditions.MelodyBuffer.GetMelody().Count == 0) //first note
                    _conditions.MelodyBuffer.InsertNote(_tempNote, 0);
                else
                    _conditions.MelodyBuffer.InsertNote(_tempNote, _gui.Cursor.GetPosition()+ 1);

                if (_gui.Cursor.GetPosition() - _gui.EditorWindow.DrawingStartIndex == _gui.EditorWindow.DisplayedNoteCounter - 1 && _gui.EditorWindow.XPos + _gui.EditorWindow.NoteWidth(_tempNote) + EditorWindow.CursorWidth > EditorWindow.MelodyFieldBound)
                    _gui.EditorWindow.DrawingStartIndex++;
                
                _gui.Cursor.IncrementPosition();
            }

            _conditions.IsFileSaved = false;
            
            _gui.EditorWindow.SetToMain();

            Reset();
        }

        private void ToggleImage(string imageName, bool select)
        {
            var setImage = (Image)ThisWindow.GetChildByName(imageName);

            setImage.Bitmap = Resources.GetBitmap((Resources.BitmapResources)((select ? _imageResources[imageName + "_1"] : _imageResources[imageName])));

            ThisWindow.FillRect(setImage.Rect);
            var backColor = setImage.Bitmap.GetPixel(0, 0);
            setImage.Bitmap.MakeTransparent(backColor);
            setImage.Invalidate();
        }

        private void TogglePitch(string imageName, bool select) //todo: try to combine this with ToggleImage
        {
            var setImage = (Image)ThisWindow.GetChildByName(imageName);

            setImage.Bitmap = Resources.GetBitmap(select? Resources.BitmapResources.note_1 : Resources.BitmapResources.note);

            var backColor = setImage.Bitmap.GetPixel(0, 0);
            setImage.Bitmap.MakeTransparent(backColor);
            setImage.Invalidate();
        }
    }
}
